#--
#   Television Episode Downloader
#   - Initial Milestone: 4-02-08
#       - Find URL from epguides.com
#       - filenames to rename_list.csv
#   - Internal Milestone 1: 4-05-08
#       - construct new name based on Template
#       - correctly interact with rename_list, make batch/sh/etc and better
#   - Internal Milestone 2: 4-06-08
#       - search an epguides.txt file and html page and fill out ep title
#
#   Rob Dennis - Lurchington Q. Delacroix ESQ. and man about town
#
#   This script is inspired and is thanks to:
#   -   Rob Meerman's tvrenamer perl script
#           http://www.robmeerman.co.uk/coding/file_renamer
#   -   Softpointer's Tag&Rename
#           http://www.softpointer.com/tr
#   
#--

import os,re,glob,time,sys,string,shutil,urllib2
from string import Template

makeRenameBatchFlag=True
quashBatchEntriesFlag=False
pretendMoveFlag=True
assumeMaxSeasonPlacesFlag=True
useUNIXnaming=False
episodePlaces=2
episodePadding=2

epguidesTxt= {"isFile":True,"filename":"epguides.txt","syntax":"epguidesTxt"}
epguidesHTML= {"isSite":True,"URL":r"http://www.epguides.com/","syntax":"epguidesHTML"}

informationSources= [epguidesTxt,epguidesHTML]

if useUNIXnaming:
    whitespaceToUnderscore = string.maketrans(" ","_")
    
def renameFileList(inList):
    newRows = []

    for row in inList:
        newRow=reshapeName(row)
        if useUNIXnaming:
            newRow=newRow.translate(whitespaceToUnderscore)

        newRows.append(newRow)

    if (makeRenameBatchFlag):
        makeRenameBatchFile("renameBatch.sh","mv",newRows,inList)

    for x in range(len(newRows)):
        if inList[x]!=newRows[x]:
            print "executing: mv",inList[x],newRows[x]
            if not pretendMoveFlag:
                shutil.move(inList[x],newRows[x])
        else:
            print "no changes needed to:",newRows[x]

def makeRenameBatchFile(fileName,command,source,dest):
    print "creating batch file"
    if quashBatchEntriesFlag:
        print "overwriting current batch"
    if len(source) != len(dest):
        print "mismatched rename lists!"
    else:
        sourceNot=[]
        destNot=[]
        if os.path.exists(fileName):
            inF=open(fileName,"rb")

            if not quashBatchEntriesFlag:
                modeString="ab"
                for line in inF.readlines():
                    if len(line)>1:
                        if line[0] != "#":
                            lineS=line.split()[1:]
                            if len(lineS)>1 and (lineS[1] in dest):
                                print lineS[1],"matched, dropped from file"
                                x=dest.index(lineS[1])
                                destNot.append(dest[x])
                                sourceNot.append(source[x])
                inF.close()
                
            else:
                modeString="wb"
        elif not pretendMoveFlag:
            modeString="wb"
            os.system("touch "+fileName)


        if not pretendMoveFlag:
            outF=open(fileName,modeString)

            if modeString=="wb":
                outF.write("#!/bin/bash\n")            
        
        for x in range(len(source)):
            if not pretendMoveFlag:
                if source[x] not in sourceNot and dest[x] not in destNot:
                    if source[x]!=dest[x]:
                        outF.write(command+" "+source[x]+" "+dest[x]+"\n")
                    else:
                        print "batch source and dest match for",source[x]
        if not pretendMoveFlag:
            outF.close()
            

def reshapeName(oldName,renameString=r"${showName} s${seasonNum}e${episodeNum}-${episodeTitle}"):
    nameTemplate=Template(renameString)

    show,season,episode,title=searchInfo(oldName)
        
    extension=oldName[oldName.rfind("."):]

    return nameTemplate.substitute(showName=show,seasonNum=str(season),episodeNum=str(episode),episodeTitle=str(title))+extension

def searchInfo(fileN):
#- Getting tv show name from folder
    shownameRE1=re.compile(r".*(?=(Season))",re.IGNORECASE)

    if shownameRE1.match(os.path.split(sys.path[0])[1]):
        showname = shownameRE1.search(os.path.split(sys.path[0])[1]).group(0).strip()
    else:
        print "no show name parsed in",os.path.split(sys.path[0])[1]
        showname="UNK"
        
#- Getting season number from filename
    seasonRE1=re.compile(r"(?<=[\ _xs\.])[0-9]+",re.IGNORECASE)
    seasonRE2=re.compile(r"^[0-9]+")
    seasonRet="UNK"
    episodeRet="UNK"
    
    if seasonRE1.search(fileN):
        seasonRet=seasonRE1.search(fileN).group(0)
    elif seasonRE2.search(fileN):
        seasonRet=seasonRE2.search(fileN).group(0)
    else:
        print "no season parsed in",fileN

    seasonIndex=fileN.find(seasonRet)+1
    
    if seasonRet != "UNK" and assumeMaxSeasonPlacesFlag:
        if len(seasonRet)>episodePlaces:
            episodeRet=seasonRet[-episodePlaces:]
            seasonRet=seasonRet[:-episodePlaces]            
            
#- Getting episode number from filename
    episodeRE1=re.compile(r"(?<=[\ _xe\.])[0-9]+",re.IGNORECASE)
    episodeRE2=re.compile(r"^[0-9]+")

    if episodeRet == "UNK":
        if episodeRE1.search(fileN):
            episodeRet=episodeRE1.search(fileN[seasonIndex:]).group(0)
        elif episodeRE2.search(fileN):
            episodeRet=episodeRE2.search(fileN[seasonIndex:]).group(0)
        else:
            print "no episode parsed in",fileN

    if episodeRet.isdigit():
        episodeRet=episodeRet.zfill(episodePadding)

#- Getting the episde title from a source
    if episodeRet.isdigit() and seasonRet.isdigit() and showname != "UNK":
        for source in informationSources:
            if source.has_key("isFile"):
                if os.path.exists(source["filename"]):
                    title=titleFromFile(source,int(seasonRet),int(episodeRet))
                    if title!=None:
                        break
            else:
                print "trying website:",source["URL"]
                title=titleFromSite(source,showname,int(seasonRet),int(episodeRet))
    else:
        title=""


    return showname,seasonRet,episodeRet,title
        

def titleFromSite(source,showname,season,episode):
##    print source["URL"]
    print "name:",showname
    print "season:",season
    print "episode:",episode

    if source["syntax"]=="epguidesHTML":
        norm = string.maketrans("","")
        pullPage=source["URL"]+showname.translate(norm,string.whitespace)
        print "searching",pullPage

    try:
        sourcePage=urllib2.urlopen(pullPage).read()
    except:
        print "no page found, continuing search\n"
        return

    if source["syntax"]=="epguidesHTML":
        sval=str(season).rjust(2)
        epval=str(episode).rjust(2)
        searchTemplate=Template(r"(?<=${seasonT}-${episodeT}.{28}).*")
        searchTemplate=searchTemplate.substitute(seasonT=sval,episodeT=epval)
        titleRE=re.compile(searchTemplate,re.IGNORECASE&re.MULTILINE)
        titleAndLink=titleRE.search(sourcePage).group(0)

        titleFieldRE=re.compile(r"(?<=>)[a-zA-Z0-9 ]*")
        return titleFieldRE.search(titleAndLink).group(0)
##        return titleRE.search(inF.read()).group(0)

    
    
    
    
def titleFromFile(source,season,episode):
    inF=open(source["filename"],"rb")

    if source["syntax"]=="epguidesTxt":
        sval=str(season).rjust(2)
        epval=str(episode).rjust(2)
        searchTemplate=Template(r"(?<=${seasonT}-${episodeT}.{28}).*")
        searchTemplate=searchTemplate.substitute(seasonT=sval,episodeT=epval)
        titleRE=re.compile(searchTemplate,re.IGNORECASE&re.MULTILINE)
        return titleRE.search(inF.read()).group(0)

def main():
    startTime=time.time()
    
    newFileNameList = []
    fileTypes = re.compile(r'.*(avi|mkv)$',re.IGNORECASE)
    fileNameList=glob.glob("*.*")
    for fileN in fileNameList:
        if fileTypes.match(fileN.strip()):
            newFileNameList.append(fileN)

    listLength=len(newFileNameList)
    print "Attempting to rename",listLength,"files"

    if listLength>0:
        renameFileList(newFileNameList)
    else:
        print "no usable files found"

    print time.time()-startTime

main()
